Creating events with Svelte actions

Posted on 2023-04-02 by

henrikvilhelmberglund

How do we create events using actions? Here's an example:

This is before we added an action, we're using a callback.


<script>
	let unlocked = false;
	let SECRET = "ArrowUp,ArrowDown,ArrowUp,ArrowDown,ArrowLeft,ArrowRight,ArrowLeft,ArrowRight";

	function onSecretComboAction(element, { secret, callback }) {
		let keys = [];
		let timeoutId = null;
		function onKeydown(event) {
			keys.push(event.key);

			if (keys.join(",") === secret) {
				callback();
			}

			if (timeoutId) clearTimeout(timeoutId);
			timeoutId = setTimeout(() => {
				timeoutId = null;
				keys = [];
				unlocked = false;
			}, 2000);
		}
		element.addEventListener("keydown", onKeydown);

		return {
			update() {},
			destroy() {
				element.removeEventListener("keydown", onKeydown);
			},
		};
	}
</script>

<input
	use:onSecretComboAction={{
		secret: SECRET,
		callback: () => {
			unlocked = true;
		},
	}} 
  />

<hr>

<input
	use:onSecretComboAction={{
		secret: "ArrowUp,ArrowDown,ArrowUp,ArrowDown,ArrowUp,ArrowDown",
		callback: () => {
			unlocked = true;
		},
	}} />

{#if unlocked}
	<div>Secret unlocked!</div>
{/if}

Another example here where we create an action and an event:

This is before we added an action.
<script>
	let count = 0;
	let timeoutId;

	function onClick() {
		if (++count === 3) {
			console.log("tripleClick!");
		}

		timeoutId && clearTimeout(timeoutId);
		timeoutId = setTimeout(() => {
			timeoutId = null;
			count = 0;
		}, 800);
	}
</script>

<button on:click={onClick}>Click me</button>

I added an extra button to make it more obvious that we can have several elements that use the same action , with differing custom event implementations , which could be pretty useful.

One important thing is to not forget to remove the event listeners in destroy()!